package dormouse.vfs;

import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * This class is the default implementation of the rootmap.
 */
public class RootMap implements IRootMap {

	/** A map containing the paths to the roots. */
	private Map<RootNames, String> roots = new HashMap<RootNames, String>();

	/** a regular expression used to identify compatible operating systems. */
	private Pattern osNameRegex = null;

	/** a regular expression used to identify compatible OS versions. */
	private Pattern osVersionRegex = null;

	/** The name of the current OS. */
	private String osName;

	/** The name of the current OS version. */
	private String osVersion;

	/**
	 * Constructor.
	 */
	public RootMap() {
		this.osName = System.getProperty("os.name");
		this.osVersion = System.getProperty("os.version");
		String home = System.getProperty("user.home");
		this.addRoot(RootNames.HOME, home);
		this.addRoot(RootNames.DOCUMENTS, home + "/Documents");
		this.addRoot(RootNames.MOVIES, home + "/Movies");
		this.addRoot(RootNames.MUSIC, home + "/Music");
		this.addRoot(RootNames.PHOTOS, home + "/Pictures");

		this.addRoot(RootNames.JAVA_HOME, System.getProperty("java.home"));
		this.addRoot(RootNames.JAVA_IO_TMP, System.getProperty("java.io.tmp"));
	}

	/**
	 * Constructor.
	 * 
	 * @param osNameRegex
	 *            a regular expression used to identify compatible operating
	 *            systems.
	 * @param osVersionRegex
	 *            a regular expression used to identify compatible OS versions.
	 */
	public RootMap(String osNameRegex, String osVersionRegex) {
		this();
		this.osNameRegex = Pattern.compile(osNameRegex);
		if (osVersionRegex != null){
			this.osVersionRegex = Pattern.compile(osVersionRegex);
		}
	}

	/**
	 * This method adds a root path to the map.
	 * 
	 * @param rootName
	 *            the name of the root (must be compatible with RootNames enum).
	 * @param path
	 *            the path to be added.
	 */
	public void addRoot(String rootName, String path) {
		roots.put(RootNames.valueOf(rootName), path);
	}

	/**
	 * This method adds a root path to the map.
	 * 
	 * @param rootName
	 *            the name of the root.
	 * @param path
	 *            the path to be added.
	 */
	public void addRoot(RootNames rootName, String path) {
		roots.put(rootName, path);
	}

	@Override
	public String getRootPath(RootNames rootName) {
		return roots.get(rootName);
	}

	@Override
	public boolean isForCurrentOS() {
		boolean isOsCompatible = true;
		boolean isVersionCompatible = true;

		if (osNameRegex != null) {
			Matcher osMatcher = osNameRegex.matcher(osName);
			isOsCompatible = osMatcher.find();
		}

		if (osVersionRegex != null) {
			Matcher osVersionMatcher = osVersionRegex.matcher(osVersion);
			isVersionCompatible = osVersionMatcher.find();
		}

		return isOsCompatible && isVersionCompatible;
	}

	/**
	 * Sets the regular expression used to identify the compatible operating
	 * system.
	 * 
	 * @param osNameRegex
	 *            the regular expression used to identify the compatible
	 *            operating system.
	 */
	public void setOsNameRegexString(String osNameRegex) {
		this.osNameRegex = (osNameRegex == null) ? null : Pattern
				.compile(osNameRegex);
	}

	/**
	 * Sets the regular expression used to identify the compatible operating
	 * system.
	 * 
	 * @param osNameRegex
	 *            the regular expression used to identify the compatible
	 *            operating system.
	 */
	public void setOsNameRegex(Pattern osNameRegex) {
		this.osNameRegex = osNameRegex;
	}

	/**
	 * Sets the regular expression used to identify the operating system
	 * version.
	 * 
	 * @param osVersionRegex
	 *            the regular expression used to identify the operating system
	 *            version.
	 */
	public void setOsVersionRegexString(String osVersionRegex) {

		this.osVersionRegex = (osVersionRegex == null) ? null : Pattern
				.compile(osVersionRegex);
	}

	/**
	 * Sets the regular expression used to identify the operating system
	 * version.
	 * 
	 * @param osVersionRegex
	 *            the regular expression used to identify the operating system
	 *            version.
	 */
	public void setOsVersionRegex(Pattern osVersionRegex) {
		this.osVersionRegex = osVersionRegex;
	}

	/**
	 * This method is used for unit testing only.
	 * 
	 * @param osName
	 *            the name of the OS to be injected.
	 */
	protected void setOsName(String osName) {
		this.osName = osName;
	}

	/**
	 * This method is used for unit testing only.
	 * 
	 * @param osVersion
	 *            the version of the OS to be injected.
	 */
	protected void setOsVersion(String osVersion) {
		this.osVersion = osVersion;
	}

	@Override
	public void setRootPath(RootNames rootName, String path) {
		roots.put(rootName, path);
	}

}
